package nodestatus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/xuelang-group/suanpan-appconnector/pkg/common"
)

const (
	WAITING  = "9"
	RUNNING  = "1"
	STOPPPED = "2"
	SUCCESS  = "3"
	FAILED   = "4"
	STARTING = "5"
	STOPPING = "6"
	DEAD     = "7"
	CRON     = "8"
	NONE     = "0"
)
const NODE_RPC_SET_NODE_STATUS_METHOD = "setNodeStatus"

type NodeStatus struct {
	NetworkId string `json:"networkId"`
	NodeId    string `json:"nodeId"`
	Status    string `json:"status"`
	Expire    *int   `json:"expire,omitempty"` //optional field
}

type NodeRpcData struct {
	Method string          `json:"method"`
	Args   json.RawMessage `json:"args"`
}

type NodeEventData struct {
	NodeId         string `json:"nodeId"`
	EventType      string `json:"eventType"`
	EventMsg       string `json:"eventMsg"`
	EventTimestamp string `json:"eventTimestamp"`
}

const UNKNOW_EXPIRE int = -2

var nodeEventCh chan NodeEventData

func init() {
	nodeEventCh = make(chan NodeEventData, 100)

	//event queue handler
	go func() {
		for {
			event := <-nodeEventCh
			pushNodeEventToMaster(event)
		}
	}()
}

func SetNodeStatus(networkId string, nodeId string, status string, expire int) error {
	logrus.Debugf("network status send, network-id:%s, nodeId:%s, status:%s, expire:%v", networkId, nodeId, status, expire)

	var exp *int = nil
	// -2 is unknow and [-1, xxxx] was valid
	if expire > -2 {
		exp = &expire

	}
	jsonStr, err := json.Marshal(&NodeStatus{
		NetworkId: networkId,
		NodeId:    nodeId,
		Status:    status,
		Expire:    exp,
	})
	if err != nil {
		return err
	}

	//post node status to master
	go func() {
		url := common.GetMasterUrl() + "/internal/networkCache/operation"
		logger := logrus.WithFields(logrus.Fields{
			"requestUrl": url,
			"reqStr":     string(jsonStr),
		})

		sendStr, err := json.Marshal(&NodeRpcData{
			Method: NODE_RPC_SET_NODE_STATUS_METHOD,
			Args:   jsonStr,
		})
		if err != nil {
			logrus.Error(err)
			return
		}
		req, err := http.NewRequest("POST", url, bytes.NewBuffer(sendStr))
		req.Header.Set("Content-Type", "application/json")
		if err != nil {
			logger.Error(err)
			return
		}

		resp, err := common.GetHttpClient().Do(req)
		if err != nil {
			logger.Error(err)
			return
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			err = fmt.Errorf("node status cache http post failed, remote response not success,status code%s", resp.Status)
			logger.Error(err)
			return
		}
	}()

	//post node events to master
	event := NodeEventData{
		NodeId:         nodeId,
		EventType:      "nodeStatusChanged",
		EventMsg:       status,
		EventTimestamp: time.Now().Format(time.RFC3339),
	}
	nodeEventCh <- event

	//if networkId == "" || nodeId == "" || status == "" {
	//	return fmt.Errorf(
	//		"set node status parameter error networkid:%s, nodeid:%s, status:%s", networkId, nodeId, status)
	//}
	//c := r.GetClient()

	////hset("networkid, node.status.nodeid, status")
	//ret := c.HSet(GetNetworkCacheKey(networkId), "node.status."+nodeId, status)
	//if !ret.Val() {
	//	return &NetworkCacheError{isHostDown: true, Err: errors.New("redis is not available")}
	//}
	return nil
}

func pushNodeEventToMaster(event NodeEventData) {
	url := common.GetServiceMasterUrl() + "/internal/nodeevents"
	logger := logrus.WithFields(logrus.Fields{
		"requestUrl": url,
	})

	sendStr, err := json.Marshal(event)
	if err != nil {
		logrus.Error(err)
		return
	}
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(sendStr))
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		logger.Error(err)
		return
	}

	resp, err := common.GetHttpClient().Do(req)
	if err != nil {
		logger.Error(err)
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		err = fmt.Errorf("node events http post failed, remote response not success,status code%s", resp.Status)
		logger.Error(err)
		return
	}
}
